package com.htstar.ovms.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.htstar.ovms.admin.api.feign.EtpInfoFeign;
import com.htstar.ovms.admin.api.vo.EtpInfoSVo;
import com.htstar.ovms.common.core.constant.CommonConstants;
import com.htstar.ovms.common.core.i18n.MsgCode;
import com.htstar.ovms.common.core.util.R;
import com.htstar.ovms.common.security.service.OvmsUser;
import com.htstar.ovms.common.security.util.SecurityUtils;
import com.htstar.ovms.device.api.dto.DeviceDTO;
import com.htstar.ovms.device.api.dto.DeviceDTONoPage;
import com.htstar.ovms.device.api.dto.DeviceExportDTO;
import com.htstar.ovms.device.api.entity.*;
import com.htstar.ovms.device.api.vo.DeviceDataVO;
import com.htstar.ovms.device.api.wrapper.OTAData;
import com.htstar.ovms.device.mapper.DeviceMapper;
import com.htstar.ovms.device.mongo.model.ObdGpsDataMG;
import com.htstar.ovms.device.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 设备
 *
 * @author flr
 * @date 2020-06-09 11:25:24
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
    @Autowired
    private DeviceAlarmService deviceAlarmService;
    @Autowired
    private DeviceConditionService deviceConditionService;

    @Autowired
    private DeviceSimService deviceSimService;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    EtpInfoFeign etpInfoFeign;

    @Autowired
    OTAUpdateService otaUpdateService;


    @Override
    //@Deprecated   标识这个方法将要改动
    public Page<DeviceDataVO> selectDevicePage(DeviceDTO deviceDTO) {
        getEtpId(deviceDTO);
        if (Objects.equals(deviceDTO.getEtpId(), null)) deviceDTO.setEtpId(0);
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(deviceDTO.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            deviceDTO.setEtpIds(etpInfoSVo.getIds());
        });
        Page<DeviceDataVO> deviceDataVOPage = baseMapper.selectDevicePage(deviceDTO);
        List<DeviceDataVO> list = new ArrayList<>();
        for (DeviceDataVO record : deviceDataVOPage.getRecords()) {
            boolean a = record.getPull().equals(1) && record.getOnline().equals("熄火");//pull==1&&online==0
            boolean b = record.getPull().equals(1) && record.getOnline().equals("异常");//pull==1&&online==3
            if (a || b) {
                record.setOnline("拔出");//这两种状态online==2
            }
            list.add(record);
        }

        return deviceDataVOPage.setRecords(list);
    }

    //    @Override
//    public Page<DeviceDataVO> selectDevicePageS(DeviceDTO deviceDTO) {
//        OvmsUser user = SecurityUtils.getUser();
//        if(deviceDTO.getEtpId() == null)deviceDTO.setEtpId(0);
//        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(deviceDTO.getEtpId());
//        currentAndParents1.forEach(etpInfoSVo -> {
//            deviceDTO.setEtpIds(etpInfoSVo.getIds());
//        });
//        return baseMapper.selectDevicePage(deviceDTO);
//    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public R removeByDeviceSns(String deviceSns) {
        boolean is_del = false;
        for (String deviceSn : deviceSns.split(",")) {
            try {
                boolean bind = baseMapper.IsBindByDeviceSn(deviceSn);
                if (bind) {
                    //提示
                    return R.failed(MsgCode.DEL_FAILED_DEVICE_BINDING.msg() + deviceSn);
                }
                //删除
                is_del = remove(new QueryWrapper<Device>().eq("device_sn", deviceSn));
                DeviceSim sim = deviceSimService.getOne(new QueryWrapper<DeviceSim>().eq("device_sn", deviceSn));
                if (null != sim) {
                    if (sim.getStartTime() != null) {
                        sim.setStartTime(sim.getStartTime());
                        sim.setEndTime(sim.getEndTime());
                    }
                    sim.setDeviceSn(null);
                    deviceSimService.updateById(sim);
                }
            } catch (Exception e) {
                log.error("编号为" + deviceSn + "删除失败", e);
            }
        }
        if (!is_del) {
            R.failed(MsgCode.DEL_FAILED.msg());
        }
        return R.ok(is_del);
    }

    @Override
    public DeviceDataVO selectDeviceDataVOByDeviceSn(String deviceSn) {
        return baseMapper.selectDeviceDataVOByDeviceSn(deviceSn);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeBindingByDeviceSns(String deviceSns, Integer isClearAll) {
        boolean removeBindingByDeviceSns = baseMapper.removeBindingByDeviceSns(Arrays.asList(deviceSns.split(",")));
        if (isClearAll != null && isClearAll == 1) {
            deviceAlarmService.remove(new QueryWrapper<DeviceAlarm>().in("device_sn", deviceSns));
            deviceConditionService.remove(new QueryWrapper<DeviceCondition>().in("device_sn", deviceSns));
            Query query = Query.query(Criteria.where("device_sn").in(deviceSns));
            mongoTemplate.remove(query, ObdGpsDataMG.class);
        }
        return removeBindingByDeviceSns;
    }

    /**
     * Description: 检测是否是允许连接的设备
     * Author: flr
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public Integer getAllowStatus(String deviceSn) {
        return baseMapper.getAllowStatus(deviceSn);
    }

    @Override
    public List<DeviceDataVO> exportDeviceInfo(DeviceExportDTO deviceDTO) {
        if (Objects.equals(deviceDTO.getEtpId(), null)) {
            deviceDTO.setEtpId(0);
        }
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(deviceDTO.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            deviceDTO.setEtpIds(etpInfoSVo.getIds());
        });
        List<String> list = null;
        if (StringUtils.isNotBlank(deviceDTO.getDeviceSns())) {
            list = Arrays.asList(deviceDTO.getDeviceSns().split(","));
        }
        List<DeviceDataVO> deviceDataVOS = baseMapper.exportDeviceInfo(deviceDTO, list);
        List<DeviceDataVO> lists = new ArrayList<>();
        for (DeviceDataVO record : deviceDataVOS) {
            boolean a = record.getPull().equals(1) && record.getOnline().equals("熄火");//pull==1&&online==0
            boolean b = record.getPull().equals(1) && record.getOnline().equals("异常");//pull==1&&online==3
            if (a || b) {
                record.setOnline("拔出");//这两种状态online==2
            }
            lists.add(record);
        }
        return lists;
    }

    @Override
    public List<DeviceDataVO> getDeviceVOByDeviceSns(String deviceSns) {
        List<DeviceDataVO> list = new ArrayList<>();
        for (String deviceSn : deviceSns.split(",")) {
            DeviceDataVO deviceDataVO = baseMapper.getDeviceVOByDeviceSns(deviceSn);
            if (deviceDataVO != null) {
                list.add(deviceDataVO);
            }
        }
        return list;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R saveDevice(Device device) {
        if (checkDeviceSn(device)) return R.failed(MsgCode.DEVICE_NUMBER_ALREADY_EXISTS.msg());
        OvmsUser user = SecurityUtils.getUser();
        device.setUserId(user.getId());
        int insert = baseMapper.insert(device);
        if (StringUtils.isNotBlank(device.getSim())) {
            updateDeviceSim(device);
        }
        return R.ok(insert);
    }

    /**
     * 跟新Sim卡
     *
     * @param device
     */
    private void updateDeviceSim(Device device) {
        DeviceSim deviceSim = new DeviceSim();

        if (StringUtils.isNotBlank(device.getSim())) {
            deviceSim.setId(Integer.parseInt(device.getSim()));
            deviceSim.setDeviceSn(device.getDeviceSn());
            DeviceSim sim = deviceSimService.getOne(new QueryWrapper<DeviceSim>().eq("id", device.getSim()));
            if(!Objects.equals(null,sim)){
                deviceSim.setStartTime(sim.getStartTime());
                deviceSim.setEndTime(sim.getEndTime());
            }
        }
        deviceSimService.updateById(deviceSim);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R updateDevice(Device device) {
        if (!checkDeviceSn(device)) return R.failed(MsgCode.MODIFICATION_FAILED_DEVICE_NOEXISTS);
        if (Objects.equals(null, device.getPurchaseDate())) {
            device.setPurchaseDate(null);
        }
        if (Objects.equals(null, device.getInvalidDate())) {
            device.setInvalidDate(null);
        }
        int update = baseMapper.updateById(device);
//        if (StringUtils.isNotBlank(device.getSim())) {
        DeviceSim sim = deviceSimService.getOne(new QueryWrapper<DeviceSim>().eq("device_sn", device.getDeviceSn()));
        if (null != sim) {
            sim.setDeviceSn(null);
            sim.setStartTime(sim.getStartTime());
            sim.setEndTime(sim.getEndTime());
            deviceSimService.updateById(sim);
        }
        updateDeviceSim(device);
//        }
        return R.ok(update);
    }


    /**
     * 检查设备是否可以绑定
     *
     * @param deviceSn
     * @return
     */
    @Override
    public R checkDeviceIsBinding(String deviceSn) {
        Integer etpId = SecurityUtils.getUser().getEtpId();
        Device device = baseMapper.selectOne(new QueryWrapper<Device>().eq("device_sn", deviceSn));
//                .eq("etp_id", etpId));
//        if (device == null) {
//            return R.failed("本企业没有此设备,绑定失败");
//        }
        if (device.getDeviceStatus() == 1) {
            return R.failed(MsgCode.THE_BINDING_FAILED);
        }
        return R.ok();
    }

    /**
     * 检查设备编号是否存在
     *
     * @param device
     * @return
     */
    private boolean checkDeviceSn(Device device) {
        if (device != null && StringUtils.isNotBlank(device.getDeviceSn())) {
            Integer count = baseMapper.selectCount(new QueryWrapper<Device>().eq("device_sn", device.getDeviceSn()));
            if (count != 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取企业ID
     *
     * @param deviceDTO
     */
    private void getEtpId(DeviceDTO deviceDTO) {
        OvmsUser user = SecurityUtils.getUser();
        if (deviceDTO.getEtpId() == null && user != null) {
            if (user.getEtpId() != CommonConstants.ETP_ID_1) {
                deviceDTO.setEtpId(user.getEtpId());
            }
        }
    }

    private void getEtpIdForExcel(DeviceDTONoPage deviceDTO) {
        OvmsUser user = SecurityUtils.getUser();
        if (deviceDTO.getEtpId() == null && user != null) {
            if (user.getEtpId() != CommonConstants.ETP_ID_1) {
                deviceDTO.setEtpId(user.getEtpId());
            }
        }
    }

    /**
     * 获取企业ID
     *
     * @param
     */
    @Override
    public int getEtpIds(String deviceSn) {
        QueryWrapper<Device> wrapper = new QueryWrapper<>();
        wrapper.eq("device_sn", deviceSn);
        Device device = baseMapper.selectOne(wrapper);
        return device.getEtpId();

    }

    /**
     * 根据设备找车辆最终找到所属车辆的用户
     */
    @Override
    public int getuserId(String deviceSn) {
        String s = baseMapper.getuserIds(deviceSn);
        if (StringUtils.isEmpty(s)) {
            return 0;
        }
        return baseMapper.getuserId(deviceSn);
    }

    /**
     * 根据设备找车辆
     */
    @Override
    public String getLicCode(String deviceSn) {
        return baseMapper.getLicCode(deviceSn);
    }

    @Override
    public Integer getCarId(String deviceSn) {
        return baseMapper.getCarId(deviceSn);
    }


    @Override
    public List<DeviceDataVO> selectDevicePageForExcel(DeviceDTONoPage deviceDTO) {
        getEtpIdForExcel(deviceDTO);
        if (Objects.equals(deviceDTO.getEtpId(), null)) deviceDTO.setEtpId(0);
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(deviceDTO.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            deviceDTO.setEtpIds(etpInfoSVo.getIds());
        });
//        Page<DeviceDataVO> page = baseMapper.selectDevicePage(deviceDTO);
        List<DeviceDataVO> page = baseMapper.selectDevicePageForExcel(deviceDTO);
        return page;
    }

    @Override
    public Page<DeviceDataVO> getbandDeviceSPage(DeviceDTO deviceDTO) {
        if (Objects.equals(deviceDTO.getEtpId(), null)) {
            deviceDTO.setEtpId(SecurityUtils.getUser().getEtpId());
        }
        return baseMapper.getbandDevicesPage(deviceDTO);
    }

    @Override
    public Page<DeviceDataVO> pageOTA(DeviceDTO deviceDTO) {
        if (deviceDTO.getOtaStatus() != null && deviceDTO.getOtaStatus() == 0) {
            return null;
        }

        getEtpId(deviceDTO);
        if (Objects.equals(deviceDTO.getEtpId(), null)) deviceDTO.setEtpId(0);
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(deviceDTO.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            deviceDTO.setEtpIds(etpInfoSVo.getIds());
        });
        Page<DeviceDataVO> deviceDataVOPage = baseMapper.selectDevicePageOtaRecord(deviceDTO);
        List<DeviceDataVO> list = new ArrayList<>();
        for (DeviceDataVO record : deviceDataVOPage.getRecords()) {
            boolean a = record.getPull().equals(1) && record.getOnline().equals("熄火");//pull==1&&online==0
            boolean b = record.getPull().equals(1) && record.getOnline().equals("异常");//pull==1&&online==3
            if (a || b) {
                record.setOnline("拔出");//这两种状态online==2
            }
            list.add(record);
        }
        return deviceDataVOPage;
    }

    @Override
    public Integer updateOTAStatus(List<String> deviceList, Integer status) {
        int i = 0;
        for (String deviceSn : deviceList) {
            Device device = new Device();
            device.setLastUpdateTime(LocalDateTime.now());
            device.setOtaStatus(status);
            UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
            deviceUpdateWrapper.eq("device_sn", deviceSn);
            int update = baseMapper.update(device, deviceUpdateWrapper);
            i += update;
        }
        return i;
    }

    @Override
    public Integer updateOTAStatusInit(OTAData req, Integer status) {
        List<String> deviceSnList = req.getDeviceSnList();
        int i = 0;//无用
        for (String deviceSn : deviceSnList) {
            QueryWrapper<Device> deviceQueryWrapper = new QueryWrapper<>();
            deviceQueryWrapper.eq("device_sn", deviceSn);
            Device device1 = baseMapper.selectOne(deviceQueryWrapper);
            //该deice已有关联的OTA记录时，对该条记录设置为已取消状态
            if (device1 != null && device1.getOtaId() != null && device1.getOtaId() != 0) {
                DeviceOta one = otaUpdateService.getById(device1.getOtaId());
                if (one != null && one.getOtaStatus() != null && one.getOtaStatus().equals(2)) {//该device的ota记录在等待中改为已取消
                    DeviceOta deviceOta = new DeviceOta();
                    deviceOta.setId(one.getId());
                    deviceOta.setOtaStatus(4);
                    otaUpdateService.updateById(deviceOta);
                }
            }
            //新增OTA记录
            DeviceOta deviceOta = new DeviceOta();
            deviceOta.setDeviceSn(deviceSn);
            deviceOta.setData(req.getData());
            deviceOta.setFailureTime(0);
            deviceOta.setSendResult(0);
            deviceOta.setUpdateResult(0);
            deviceOta.setOtaStatus(2);
            deviceOta.setRemark(req.getRemark());
            deviceOta.setCreateTime(LocalDateTime.now());
            if (device1 != null) {
                deviceOta.setBindTime(device1.getCreateTime());
            }
//            deviceOta.setUpdateTime(LocalDateTime.now());
//            deviceOta.setLastUpdateTime(LocalDateTime.now());
            otaUpdateService.save(deviceOta);
            ///
            if (device1 != null) {
                Device device = new Device();
                device.setId(device1.getId());
                device.setLastUpdateTime(LocalDateTime.now());
                device.setOtaStatus(status);
                device.setOtaId(deviceOta.getId());
                int update = baseMapper.updateById(device);
                i += update;
            }
        }
        return i;
    }

    /**
     * OTA指令下发执行错误
     *
     * @param deviceSn
     */
    @Override
    public void OTAfaild(String deviceSn) {
        QueryWrapper<Device> deviceQueryWrapper1 = new QueryWrapper<>();
        deviceQueryWrapper1.eq("device_sn", deviceSn);
        Device device1 = baseMapper.selectOne(deviceQueryWrapper1);
        Integer otaId = device1.getOtaId();
        //device
        ArrayList<String> deviceSnList = new ArrayList<String>();
        deviceSnList.add(deviceSn);
        this.updateOTAStatus(deviceSnList, 3);

        QueryWrapper<Device> deviceQueryWrapper = new QueryWrapper<>();
        deviceQueryWrapper.eq("device_sn", deviceSn);
        Device one = this.getOne(deviceQueryWrapper);
        //同步OTA表失败次数
        DeviceOta deviceOta = new DeviceOta();
        deviceOta.setId(otaId);
        deviceOta.setFailureTime(one.getFailureTime());
        deviceOta.setOtaStatus(3);
        otaUpdateService.updateById(deviceOta);
        if (one.getFailureTime() < 3) {//不足3次
            Device device = new Device();
            device.setFailureTime(one.getFailureTime() + 1);
            UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
            deviceUpdateWrapper.eq("device_sn", deviceSn);
            this.update(device, deviceUpdateWrapper);
            DeviceOta deviceOta2 = new DeviceOta();
            deviceOta2.setId(otaId);
            deviceOta2.setOtaStatus(3);
            deviceOta2.setFailureTime(one.getFailureTime() + 1);
            otaUpdateService.updateById(deviceOta2);
        }
    }
}
